/*
 * Copyright 2007 Google Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License"); you may not
 * use this file except in compliance with the License. You may obtain a copy of
 * the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0

 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the

 * License for the specific language governing permissions and limitations under
 * the License.
 */

package com.google.gwt.util.compat;

import java.text.MessageFormat;
import java.util.Collections;
import java.util.List;
import java.util.ListIterator;
import java.util.NoSuchElementException;
import javax.lang.model.element.Modifier;

public class APIComparator {
  public static final String
      ADDCLASS = "+ class: {0}\n\n",
      DELCLASS = "- class: {0}\n\n",
      FORCLASS = "In class {0} :\n",
      VISCHANGE = "    Visibility change: from {0} to {1}\n",
      INHCHANGE = "  Parent change: from {0} to {1}\n",
      ADDINTERFACE = "  + interface: {0}\n",
      DELINTERFACE = "  - interface: {0}\n",
      ADDFIELD = "  + field: {0}\n",
      DELFIELD = "  - field: {0}\n",
      FORFIELD = "  For field {0} :\n",
      DELMETHOD = "  - method: {0}\n",
      ADDMETHOD = "  + method: {0}\n",
      FORMETHOD = "  For method {0} :\n",
      ADDEXCEPTION = "    + exception: {0}\n",
      DELEXCEPTION = "    - exception: {0}\n";
  
  
  public static String compareLists(List<ClassNode> list1, List<ClassNode> list2) {
    String retValue = "";
    
    for (ClassNode cn : list1) {
      int index = Collections.binarySearch(list2, cn);
      if (index < 0)
        retValue += MessageFormat.format(DELCLASS, cn);
      else {
        String temp = compareClasses(cn, list2.get(index));
        if (!temp.equals(""))
          retValue += MessageFormat.format(FORCLASS, cn) + temp + "\n";
        list2.remove(index);
      }
    }
    for (ClassNode cn : list2)
      retValue += MessageFormat.format(ADDCLASS, cn);
    
    return retValue;
  }
  
  public static String compareClasses(ClassNode c1, ClassNode c2) {
    String retValue = "";
    
    if (c1.mods.contains(Modifier.PUBLIC) && c2.mods.contains(Modifier.PROTECTED))
      retValue += MessageFormat.format(VISCHANGE, Modifier.PUBLIC, Modifier.PROTECTED);
    else if (c1.mods.contains(Modifier.PROTECTED) && c2.mods.contains(Modifier.PUBLIC))
      retValue += MessageFormat.format(VISCHANGE, Modifier.PROTECTED, Modifier.PUBLIC);
    if (!c1.parent.equals(c2.parent))
      retValue += MessageFormat.format(INHCHANGE, c1.parent, c2.parent);
    
    for (String iface : c1.ifaces) {
      int index = Collections.binarySearch(c2.ifaces, iface);
      if (index < 0)
        retValue += MessageFormat.format(DELINTERFACE, iface);
      else
        c2.ifaces.remove(index);
    }
    for (String iface : c2.ifaces)
      retValue += MessageFormat.format(ADDINTERFACE, iface);
    
    for (FieldNode fn : c1.fields) {
      int index = Collections.binarySearch(c2.fields, fn);
      if (index < 0)
        retValue += MessageFormat.format(DELFIELD, fn);
      else {
        retValue += compareFields(fn, c2.fields.get(index));
        c2.fields.remove(index);
      }
    }
    for (FieldNode fn : c2.fields)
      retValue += MessageFormat.format(ADDFIELD, fn);
    
    for (MethodNode mn : c1.methods) {
      int index = Collections.binarySearch(c2.methods, mn);
      if (index < 0)
        retValue += MessageFormat.format(DELMETHOD, mn);
      else {
        retValue += compareMethods(mn, c2.methods.get(index));
        c2.methods.remove(index);
      }
    }
    for (MethodNode mn : c2.methods)
      retValue += MessageFormat.format(ADDMETHOD, mn);
    
    return retValue;
  }

  private static String compareFields(FieldNode f1, FieldNode f2) {
    String retValue = "";
    
    if (f1.mods.contains(Modifier.PUBLIC) && f2.mods.contains(Modifier.PROTECTED))
      retValue += MessageFormat.format(FORFIELD, f1) + 
          MessageFormat.format(VISCHANGE, Modifier.PUBLIC, Modifier.PROTECTED);
    if (f1.mods.contains(Modifier.PROTECTED) && f2.mods.contains(Modifier.PUBLIC))
      retValue += MessageFormat.format(FORFIELD, f1) +
          MessageFormat.format(VISCHANGE, Modifier.PROTECTED, Modifier.PUBLIC);
    
    return retValue;
  }

  private static String compareMethods(MethodNode m1, MethodNode m2) {
    String retValue = "";
    
    if (m1.mods.contains(Modifier.PUBLIC) && m2.mods.contains(Modifier.PROTECTED))
      retValue += MessageFormat.format(FORMETHOD, m1) + 
          MessageFormat.format(VISCHANGE, Modifier.PUBLIC, Modifier.PROTECTED);
    if (m1.mods.contains(Modifier.PROTECTED) && m2.mods.contains(Modifier.PUBLIC))
      retValue += MessageFormat.format(FORMETHOD, m1) +
          MessageFormat.format(VISCHANGE, Modifier.PROTECTED, Modifier.PUBLIC);
    for (String exc : m1.exceptions)
      if (m2.exceptions.contains(exc))
        m2.exceptions.remove(exc);
      else
        retValue += MessageFormat.format(FORMETHOD, m1) +
            MessageFormat.format(DELEXCEPTION, exc);
    for (String exc : m2.exceptions)
      retValue += MessageFormat.format(FORMETHOD, m2) +
          MessageFormat.format(ADDEXCEPTION, exc);
    return retValue;
  }
  
}
